//	--------------------------------------------------------------------
//	Copyright(C) 2006,2007 Zhao Yukun. All rights reserved.
//	This file is a part of the Xeres system.
//	Xeres 2007
//	Contact : xeres.engine@gmail.com
//	$(reservedInfo)
//	$(reservedDeclaration)
//	--------------------------------------------------------------------
///	@file	<RenderContext.h>
///	@path	~/src/graphics/
///	@date	2007/10/11
///	@desc	Render Context.

#pragma once

#include "xeres.h"

#include "lib/math/matrix.h"
#include "lib/math/color.h"
#include "lib/math/rect.h"

#include "graphics/IDevice.h"
#include "graphics/DxMath.h"

// DirectX 9 is also needed
#include <d3d9.h>

// DirectX 10 header files
#include <d3d10.h>

namespace xeres {

	// forward declaration
	class CDevice9;
	class CDevice10;
	class IRenderer;
	class CRenderer9;
	class CRenderer10;
	class IPass;
	class IView;
	class IEffect;
	class IEffectPool;
	class IShader;
	class IShaderVariable;
	class ITexture;

	/*!
		\class	RenderContext
		\brief	Provide a render-time context for rendering manipulation.

		\sa IDevice, IRenderer
	*/
	class ALIGNED RenderContext
	{
	protected:

		/// \name Constructor & Destructor
		//@{

		/// \ctor
		RenderContext( void );

		/// \dtor
		~RenderContext( void );

		//@}

		/// \name Internal Manipulation
		//@{

		/// \brief		Setup render context.
		void Setup( RefWeak<IDevice> device , RefWeak<IRenderer> renderer );

		/// \brief		Initialize render context.
		void Initialize( void );

		/// \brief		Finalize render context.
		void Finalize( void );

		//@}

	public:

		/// \name		Device Reset Related
		//@{

		/// \brief		Resized
		void Resized( void );

		///	\brief		Callback to invoke device size check.
		void DeviceOnSize( void * window , bool miminized );

		///	\brief		Callback to invoke enter sizing.
		void DeviceOnEnterSizing( void * window );

		///	\brief		Callback to invoke enter sizing.
		void DeviceOnExitSizing( void * window );

		//@}

		/// \name Query Device & Renderer
		//@{

		///	\brief		Determine if device is valid.
		bool IsDeviceValid( void ) const { return m_device.IsValid(); }

		///	\brief		Get rendering device.
		RefWeak<IDevice> GetDevice( void ) const { return m_device; }

		///	\brief		Shortcut to get directX 9 device. Return NULL when using DX 10.
		RefWeak<CDevice9> GetDevice9( void ) const { return m_device9; }

		///	\brief		Shortcut to get directX 10 device. Return NULL when using DX 9.
		RefWeak<CDevice10> GetDevice10( void ) const { return m_device10; }

		///	\brief		Get renderer instance.
		RefWeak<IRenderer> GetRenderer( void ) const { return m_renderer; }

		///	\brief		Shortcut to get DX9 renderer.
		RefWeak<CRenderer9> GetRenderer9( void ) const { return m_renderer9; }

		///	\brief		Shortcut to get DX 10 renderer.
		RefWeak<CRenderer10> GetRenderer10( void ) const { return m_renderer10; }

		///	\brief		Get raw interface of dx9.
		IDirect3DDevice9 * GetDX9( void ) const { return m_dx9; }

		///	\brief		Get raw interface of dx10.
		ID3D10Device * GetDX10( void ) const { return m_dx10; }

		/// \brief		Toggle full screen.
		void ToggleFullScreen( void );

		//@}

		/// \name Query Graphics States
		//@{

		///	\brief		Get resolution width.
		template<typename _Ty> _Ty ResX( void ) const { return _Ty(m_xres_i); }
		template<>float ResX<float>( void ) const { return m_xres_f; }

		///	\brief		Get resolution height.
		template<typename _Ty> _Ty ResY( void ) const  { return _Ty(m_yres_i); }
		template<>float ResY<float>( void ) const { return m_yres_f; }

		/// \brief		Process raster vertex to screen coordinate. Position MUST be a 4 component float at the beginning of vertex.
		void ProcessRasterCoord( void * vertex , size_t stride , size_t count );

		/// \brief		Process raster vertex to screen coordinate. By specifying factor.
		void ProcessRasterCoord( void * vertex , size_t stride , size_t count , float invx2 , float invy2 );

		/// \brief		Fix screen coordinates to texture coordinates.
		void FixRasterTextureCoord( void * vertex , float w , float h , size_t offset , size_t stride , size_t count );

		/// \brief		Fix screen coordinates to texture coordinates.
		Pair<float> GetRasterTextureCoord( float w , float h );

		/// \brief		Set viewport.
		void SetViewport( uint x , uint y , uint w , uint h , float minz , float maxz );

		/// \brief		Get viewport.
		void GetViewport( Rect<int>& rect , float& minz , float& maxz );

		/// \brief		Restore viewport.
		void RestoreViewport( void );

		//@}

		/// \name Clear Functions
		//@{

		///	\brief		Clear buffer's color and depth.
		void ClearColorAndDepth( const PackColor4& color , float depth );

		///	\brief		Clear buffer's color.
		void ClearColor( const PackColor4& color );

		///	\brief		Clear buffer's depth.
		void ClearDepth( float depth );

		//@}

	protected:

		/// \name Render Flow Management
		//@{

		/// \brief	Begin scene.
		void BeginScene( void );

		/// \brief	End scene.
		void EndScene( void );

		//@}

		/// \name Pass Rendering Methods
		//@{

		/// \brief	Set render pass.
		void SetRenderPass( RefWeak<IPass> pass );

	public:
		/// \brief	Get render pass.
		RefWeak<IPass> GetRenderPass( void ) { return m_currentPass; }

		/// \brief	Get render view.
		RefWeak<IView> GetRenderView( void ) { return m_currentView; }

		/// \brief	Get view project.
		const Matrix<float>& GetViewProj( void ) { return m_currentViewProj; }

		//@}

		/// \name Draw methods.
		//@{

		//@}

	protected:

		//@ data

		// device
		Ref<IDevice>				m_device;
		// renderer
		Ref<IRenderer>				m_renderer;

	private:
		// for fast access
		// device
		RefWeak<CDevice9>			m_device9;
		RefWeak<CDevice10>			m_device10;
		// object
		IDirect3DDevice9 *			m_dx9;
		ID3D10Device *				m_dx10;
		// renderer
		RefWeak<CRenderer9>			m_renderer9;
		RefWeak<CRenderer10>		m_renderer10;

		// render context info
		RefWeak<IPass>				m_currentPass;
		RefWeak<IView>				m_currentView;

		Matrix<float>				m_currentViewProj;

		// screen resolution
		int							m_xres_i , m_yres_i;
		float						m_xres_f , m_yres_f;
		float						m_inv_xres_f , m_inv_yres_f;
		float						m_xres_f2 , m_yres_f2;
		float						m_inv_xres_f2 , m_inv_yres_f2;

		// render target
		IDirect3DSurface9 *			m_rt9[8];
		ID3D10RenderTargetView *	m_rt10[8];
		ID3D10DepthStencilView *	m_ds10;

	};

} // namespace xeres
